// Codec2.h: interface for the CCodec2 class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_CODEC2_H__94873FD4_4C60_4EE0_9D9D_81F8806DA1B8__INCLUDED_)
#define AFX_CODEC2_H__94873FD4_4C60_4EE0_9D9D_81F8806DA1B8__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "wtypes.h"

#include "../../Include/CommonDefine.h"				// 2010-06-04(pdj) : set path...

#include "AES_Define.h"
#include "UnicodeMethod.h"
#include <atlstr.h>

#define DWORD_MAXIMUM_LENGTH 0xFFFFFFFF

const static BYTE encodeX = 0xE7;
const static DWORD encodeDX = 0xE74C12FB;

#define _swap(a, b)	((a) ^= (b) ^= (a) ^= (b))

#define MIN(a, b) (((a) < (b))? (a):(b))
#define MAX(a, b) (((a) > (b))? (a):(b))

const static char toHexCode[] = "0123456789ABCDEF";

// The 7-bit alphabet used to encode binary information
static char base64_table[] =
{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0'
};

//#include "LibUtility.h"
//class LIB_UTILITY_DLLAPI CCodec
class CCodec
{
public:
	const static int US_ASCII;
	const static int EUC_KR;
	const static int ISO_2022_KR;
	const static int ISO_2022_JP;
	const static int EUC_JP;
	const static int SHIFT_JIS;
	const static int ISO_8859_1;

	const static char ET_RAW;
	const static char ET_BASE64;
	const static char ET_QP;
	
public:
	// Use Only ANSI String
	static void JGG_EncryptW(char *szStr, LPCTSTR szKey);
	static void JGG_Encrypt(char *szStr, LPCSTR szKey);
	static void JGG_DecryptW(char *szStr, LPCTSTR szKey);
	static void JGG_Decrypt(char *szStr, LPCSTR szKey);

	static CString EncodeCMN(const CString& strPlain);
	static CString DecodeCMN(const CString& strCipher);

	///////////////////////////////
	// MODE = CFB	Padding = NO Padding
	static string EncodeAES(_tstring &strPlainText, LPCTSTR strEncKey);

	///////////////////////////////
	// MODE = CFB	Padding = NO Padding
	static _tstring DecodeAES(string &strCipherText, LPCTSTR strDecKey);
		
	// URL Encode Function..
	static _tstring UrlEncode(const _tstring &strValue, int nTransferType = TYPE_ANSI);
	static _tstring UrlDecode(const _tstring &strValue, int nTransferType = TYPE_ANSI);
	
	static string UrlEncode_Stream(const _tstring &strValue, int nTransferType = TYPE_ANSI);

	static CString EncodeURL(const CString& strValue, int nTransferType = TYPE_ANSI);
	static CString DecodeURL(const CString& strValue, int nTransferType = TYPE_ANSI);

	static _tstring Nate2Encode(LPCTSTR szText, int nTextLen = -1);
	static _tstring Nate2Decode(LPCTSTR szText, int nTextLen = -1);

	static string Nate2EncodeA(const char *szText, int nTextLen = -1);
	static wstring Nate2EncodeW(const wchar_t *szText, int nTextLen = -1);

	static string Nate2DecodeA(const char *szText, int nTextLen = -1);
	static wstring Nate2DecodeW(const wchar_t *szText, int nTextLen = -1);

	static CString TkEncode3(LPCTSTR plain);
	static void TkEncode3A(LPCSTR plain,string &strRet);
	static CString TkDecode3(LPCTSTR szEncStr);
	static void TkDecode3A(LPCSTR szEncStr,string &strRet);
	static CString TkEncode3_100(LPCTSTR plain);
	static CString TkDecode3_100(LPCTSTR szEncStr);

	//////////
	// BASE64 Encoding
	static void Base64Encode(const string& strSrc, unsigned long ulLength, 
															string &rstrRes, bool bNewLine=true);
	static void Base64Decode(const string& strSrc, string& rstrRes, bool bBinary=true);

	//////////
	//Quoted Printable
	static void QPEncode(const string& strMsg, unsigned long ulLength, string& rstrRes);
	static bool QPDecode(const string& strSrc, string& rstrRes, bool bBinary=true);

	/////////
	// MD5 -> Not General MD5 Encoding
	static string NateMD5A(const string& strInput);
	static _tstring NateMD5W(const _tstring& strInput);
	
	static string NateBase64A(const string& strInput, const unsigned long& ulSize);
	static _tstring NateBase64W(const _tstring& strInput, const unsigned long& ulLength);

	static string Unicode2EUC(const string &strData, bool bUseEscape=false);
	static string EncodeCharset(const string &strFromSet, const string &strData, string strCharSet, bool bEndISOTag=false);
	static string CvtUTF8(const string &strFromSet, const string & strData);
	static string CvtISOJP(const string & strFromSet, const string & strData, bool bEndISOTag=false);
	static string CvtISOKR(const string & strFromSet, const string & strData);
	static string CvtSJIS(const string & strFromSet, const string & strData);
	static string CvtEUCKR(const string & strFromSet, const string & strData);
	static string UTF82EUC(const string & rstrUTF);
	
	static string EncodeHeaderString(const string& strInputParam, char cCodecType, string strCharset, bool bNewLine = true);
	static string DecodeHeaderString(const string& strInput, bool bLtgtConvertMode=false);

	//////////
	//	iso2022-kr -> euckr(ksc5601)
	static string ISO2EUCKR(const string & rstrISO);

	//////////
	//	iso2022-jp -> shift-jis
	static string ISO2SJIS(const string & rstrISO);
		
	static string Convert_lt_gt(const string &strInput);

	// For TKEncode / TKDecode
	static _tstring _HaxDump(BYTE * pData, int len);
	static void _HaxDumpA(BYTE *pData, int len, string &strRet);

	// For URL Encode / Decode
	static string _UrlEncodeA(const string &strValue);
	static string _UrlDecodeA(const string &strValue);
private:
	// For Nate2Decode, Nate2Encode
	static BOOL _IsRequireNate2EncodingA( char c );
	static BOOL _IsRequireNate2EncodingW( wchar_t c );
	

	static int _Nate2EncodeA( const char *pRaw, int nRawLen, string &strDest, int nBufferLen );
	static int _Nate2EncodeW( const wchar_t *pRaw, int nRawLen, wstring &strDest, int nBufferLen );
	
	static int _Nate2DecodeA( const char *pRaw, int nRawLen, string &strDest, int nBufferLen );
	static int _Nate2DecodeW( const wchar_t *pRaw, int nRawLen, wstring &strDest, int nBufferLen );

	static void _DecToHexA( int dec, char *hex, int len );
	static void _DecToHexW( int dec, wchar_t *hex, int len );
		
	static char _HexDecToCharA( char num );
	static wchar_t _HexDecToCharW( wchar_t num );
	
	static int _HexToDecA(const char *hex, int len);
	static int _HexToDecW(const wchar_t *hex, int len);

	// For AES Encode / Decode
	static DWORD EncodeAESA(BYTE *szPlainText, BYTE *szCipherText, int *nCipherTextLength /*OUT*/, 
							BYTE *szEncKey, BYTE *szIV = NULL, DWORD nEncMode = AI_CFB, 
							DWORD nPaddingMode = AI_PKCS_PADDING);
	static DWORD DecodeAESA(BYTE *szCipherText, int nCipherTextLength /*IN*/, BYTE *szPlainText, 
							int *nPlainTextLength /*OUT*/, BYTE *szDecKey, BYTE *szIV = NULL, 
							DWORD nDecMode = AI_CFB, DWORD nPaddingMode = AI_PKCS_PADDING);

	static void _GenTabs(void);
	
	static void _RIJNDAEL_KeySchedule(BYTE	*UserKey, DWORD	k_len, DWORD *e_key);
	
	static DWORD _AES_EncKeySchedule(BYTE *UserKey, DWORD UserKeyLen, AES_ALG_INFO *AlgInfo);
	static DWORD _AES_DecKeySchedule(BYTE *UserKey, DWORD UserKeyLen, AES_ALG_INFO *AlgInfo);
	
	static void _AES_Encrypt(void *CipherKey, BYTE *Data);
	static void _AES_Decrypt(void *CipherKey, BYTE *Data);
	
	static void _AES_SetAlgInfo(DWORD ModeID, DWORD PadType, BYTE *IV, AES_ALG_INFO *AlgInfo);
	
	static DWORD _PaddSet(BYTE *pbOutBuffer, DWORD dRmdLen, DWORD dBlockLen, DWORD dPaddingType);
	static DWORD _PaddCheck(BYTE *pbOutBuffer, DWORD dBlockLen, DWORD dPaddingType);
	
	static DWORD _AES_EncInit(AES_ALG_INFO *AlgInfo);
	
	static DWORD _ECB_EncUpdate(AES_ALG_INFO *AlgInfo, BYTE *PlainTxt, DWORD PlainTxtLen, BYTE *CipherTxt, DWORD *CipherTxtLen);
	static DWORD _CBC_EncUpdate(AES_ALG_INFO *AlgInfo, BYTE *PlainTxt, DWORD PlainTxtLen, BYTE *CipherTxt, DWORD *CipherTxtLen);
	static DWORD _OFB_EncUpdate(AES_ALG_INFO *AlgInfo, BYTE *PlainTxt, DWORD PlainTxtLen, BYTE *CipherTxt, DWORD *CipherTxtLen);
	static DWORD _CFB_EncUpdate(AES_ALG_INFO *AlgInfo, BYTE *PlainTxt, DWORD PlainTxtLen, BYTE *CipherTxt, DWORD *CipherTxtLen);
	static DWORD _AES_EncUpdate(AES_ALG_INFO *AlgInfo, BYTE *PlainTxt, DWORD PlainTxtLen, BYTE *CipherTxt, DWORD *CipherTxtLen);
	
	static DWORD _ECB_EncFinal(AES_ALG_INFO *AlgInfo, BYTE *CipherTxt, DWORD *CipherTxtLen);
	static DWORD _CBC_EncFinal(AES_ALG_INFO *AlgInfo, BYTE *CipherTxt, DWORD *CipherTxtLen);
	static DWORD _OFB_EncFinal(AES_ALG_INFO *AlgInfo, BYTE *CipherTxt, DWORD *CipherTxtLen);
	static DWORD _CFB_EncFinal(AES_ALG_INFO *AlgInfo, BYTE *CipherTxt, DWORD *CipherTxtLen);
	static DWORD _AES_EncFinal(AES_ALG_INFO *AlgInfo, BYTE *CipherTxt, DWORD *CipherTxtLen);
	
	static DWORD _AES_DecInit(AES_ALG_INFO *AlgInfo);
	
	static DWORD _ECB_DecUpdate(AES_ALG_INFO *AlgInfo, BYTE *CipherTxt, DWORD CipherTxtLen, BYTE *PlainTxt, DWORD *PlainTxtLen);
	static DWORD _CBC_DecUpdate(AES_ALG_INFO *AlgInfo, BYTE *CipherTxt, DWORD CipherTxtLen, BYTE *PlainTxt, DWORD *PlainTxtLen);
	static DWORD _OFB_DecUpdate(AES_ALG_INFO *AlgInfo, BYTE *CipherTxt, DWORD CipherTxtLen, BYTE *PlainTxt, DWORD *PlainTxtLen);
	static DWORD _CFB_DecUpdate(AES_ALG_INFO *AlgInfo, BYTE *CipherTxt, DWORD CipherTxtLen, BYTE *PlainTxt, DWORD *PlainTxtLen);
	static DWORD _AES_DecUpdate(AES_ALG_INFO *AlgInfo, BYTE *CipherTxt, DWORD CipherTxtLen, BYTE *PlainTxt, DWORD *PlainTxtLen);
	
	static DWORD _ECB_DecFinal(AES_ALG_INFO *AlgInfo, BYTE *PlainTxt, DWORD *PlainTxtLen);
	static DWORD _CBC_DecFinal(AES_ALG_INFO *AlgInfo, BYTE *PlainTxt, DWORD *PlainTxtLen);
	static DWORD _OFB_DecFinal(AES_ALG_INFO *AlgInfo, BYTE *PlainTxt, DWORD *PlainTxtLen);
	static DWORD _CFB_DecFinal(AES_ALG_INFO *AlgInfo, BYTE *PlainTxt, DWORD *PlainTxtLen);
	static DWORD _AES_DecFinal(AES_ALG_INFO *AlgInfo, BYTE *PlainTxt, DWORD *PlainTxtLen);
	
	// For Convert Character-Set
	static bool _SJIS2WC(wchar_t &wc, unsigned char c1, unsigned char c2);
	static bool _WC2KSC5601(wchar_t wc, string & rstrData, unsigned char &rC1, unsigned char &rC2);
	static bool _KSC56012WC(wchar_t &wc, unsigned char c1, unsigned char c2);
	static bool _WC2SJIS_0208(wchar_t wc, string &rstrData, unsigned char &rC1, unsigned char &rC2);

	// For EncodeCMN, DecodeCMN
	static inline DWORD _EncodeDWORD(DWORD dw) {return dw ^ encodeDX;}
	static inline BYTE _EncodeByte(BYTE bt) {return bt ^ encodeX;}
	static inline BYTE _SwapQurt(BYTE bt) {return ((bt & (BYTE)0xF0) >> 4) | ((bt & (BYTE)0x0F) << 4);}
	static TCHAR* _HexEncode(const LPBYTE pByte, int byteLen);
	static BYTE* _HexDecode(const TCHAR* pChar, int* byteLen);
	static TCHAR _toCharCode(TCHAR ch);
	static inline char _CheckNull(char ch) {return (ch==0)? ' ':ch;}

	// For URL Decode
	static char _Hexa2Char(char hex_up, char hex_low);

	// For Nate MD5 Encoding
	static int _add(int x, int y)
	{
		return (x & 0x7fffffff) + (y & 0x7fffffff) ^ x & 0x80000000 ^ y & 0x80000000;
	}
	
	static int _rol(int num, int cnt)
	{
		return num << cnt | unsigned(num) >> (32 - cnt);
	}
	
	static int _cmn(int q, int a, int b, int x, int s, int t)
	{
		return _add(_rol(_add(_add(a, q), _add(x, t)), s), b);
	}
	
	static int _ff(int a, int b, int c, int d, int x, int s, int t)
	{
		return _cmn(b & c | ~b & d, a, b, x, s, t);
	}
	
	static int _gg(int a, int b, int c, int d, int x, int s, int t)
	{
		return _cmn(b & d | c & ~d, a, b, x, s, t);
	}
	
	static int _hh(int a, int b, int c, int d, int x, int s, int t)
	{
		return _cmn(b ^ c ^ d, a, b, x, s, t);
	}
	
	static int _ii(int a, int b, int c, int d, int x, int s, int t)
	{
		return _cmn(c ^ (b | ~d), a, b, x, s, t);
	}
};

#endif // !defined(AFX_CODEC2_H__94873FD4_4C60_4EE0_9D9D_81F8806DA1B8__INCLUDED_)
